/*
 * FreeRTOS V202212.00
 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * https://www.FreeRTOS.org
 * https://github.com/FreeRTOS
 *
 */

/******************************************************************************
 * >>>>>> NOTE 1: <<<<<<
 *
 * main() can be configured to create either a very simple LED flasher demo, or
 * a more comprehensive test/demo application.
 *
 * To create a very simple LED flasher example, set the
 * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY constant (defined below) to 1.  When
 * this is done, only the standard demo flash tasks are created.  The standard
 * demo flash example creates three tasks, each of which toggle an LED at a
 * fixed but different frequency.
 *
 * To create a more comprehensive test and demo application, set
 * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY to 0.
 *
 * >>>>>> NOTE 2: <<<<<<
 *
 * In addition to the normal set of standard demo tasks, the comprehensive test
 * makes heavy use of the floating point unit, and forces floating point
 * instructions to be used from interrupts that nest three deep.  The nesting
 * starts from the tick hook function, resulting is an abnormally long context
 * switch time.  This is done purely to stress test the FPU context switching
 * implementation, and that part of the test can be removed by setting
 * configUSE_TICK_HOOK to 0 in FreeRTOSConfig.h.
 ******************************************************************************
 *
 * main() creates all the demo application tasks and software timers, then starts
 * the scheduler.  The web documentation provides more details of the standard
 * demo application tasks, which provide no particular functionality, but do
 * provide a good example of how to use the FreeRTOS API.
 *
 * In addition to the standard demo tasks, the following tasks and tests are
 * defined and/or created within this file:
 *
 * "Reg test" tasks - These fill both the core and floating point registers with
 * known values, then check that each register maintains its expected value for
 * the lifetime of the task.  Each task uses a different set of values.  The reg
 * test tasks execute with a very low priority, so get preempted very
 * frequently.  A register containing an unexpected value is indicative of an
 * error in the context switching mechanism.
 *
 * "Check" timer - The check software timer period is initially set to three
 * seconds.  The callback function associated with the check software timer
 * checks that all the standard demo tasks, and the register check tasks, are
 * not only still executing, but are executing without reporting any errors.  If
 * the check software timer discovers that a task has either stalled, or
 * reported an error, then it changes its own execution period from the initial
 * three seconds, to just 200ms.  The check software timer callback function
 * also toggles an LED each time it is called.  This provides a visual
 * indication of the system status:  If the LED toggles every three seconds,
 * then no issues have been discovered.  If the LED toggles every 200ms, then
 * an issue has been discovered with at least one task.
 *
 * Tick hook - The application tick hook is called from the schedulers tick
 * interrupt service routine when configUSE_TICK_HOOK is set to 1 in
 * FreeRTOSConfig.h.  In this example, the tick hook is used to test the kernels
 * handling of the floating point units (FPU) context, both at the task level
 * and when nesting interrupts access the floating point unit registers.  The
 * tick hook function first fills the FPU registers with a known value, it
 * then triggers a medium priority interrupt.  The medium priority interrupt
 * fills the FPU registers with a different value, and triggers a high priority
 * interrupt.  The high priority interrupt once again fills the the FPU
 * registers with a known value before returning to the medium priority
 * interrupt.  The medium priority interrupt checks that the FPU registers
 * contain the values that it wrote to them, then returns to the tick hook
 * function.  Finally, the tick hook function checks that the FPU registers
 * contain the values that it wrote to them, before it too returns.
 *
 * Button interrupt - The button marked "USER" on the starter kit is used to
 * demonstrate how to write an interrupt service routine, and how to synchronise
 * a task with an interrupt.  A task is created that blocks on a test semaphore.
 * When the USER button is pressed, the button interrupt handler gives the
 * semaphore, causing the task to unblock.  When the task unblocks, it simply
 * increments an execution count variable, then returns to block on the
 * semaphore again.
 */

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"

/* Demo application includes. */
#include "partest.h"
#include "flash.h"
#include "flop.h"
#include "integer.h"
#include "PollQ.h"
#include "semtest.h"
#include "dynamic.h"
#include "BlockQ.h"
#include "blocktim.h"
#include "countsem.h"
#include "GenQTest.h"
#include "recmutex.h"
#include "death.h"

/* Hardware and starter kit includes. */
#include "arm_comm.h"
#include "iar_stm32f407zg_sk.h"
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"

/* Priorities for the demo application tasks. */
#define mainFLASH_TASK_PRIORITY                    ( tskIDLE_PRIORITY + 1UL )
#define mainQUEUE_POLL_PRIORITY                    ( tskIDLE_PRIORITY + 2UL )
#define mainSEM_TEST_PRIORITY                      ( tskIDLE_PRIORITY + 1UL )
#define mainBLOCK_Q_PRIORITY                       ( tskIDLE_PRIORITY + 2UL )
#define mainCREATOR_TASK_PRIORITY                  ( tskIDLE_PRIORITY + 3UL )
#define mainFLOP_TASK_PRIORITY                     ( tskIDLE_PRIORITY )

/* The LED used by the check timer. */
#define mainCHECK_LED                              ( 3UL )

/* A block time of zero simply means "don't block". */
#define mainDONT_BLOCK                             ( 0UL )

/* The period after which the check timer will expire, in ms, provided no errors
 * have been reported by any of the standard demo tasks.  ms are converted to the
 * equivalent in ticks using the portTICK_PERIOD_MS constant. */
#define mainCHECK_TIMER_PERIOD_MS                  ( 3000UL / portTICK_PERIOD_MS )

/* The period at which the check timer will expire, in ms, if an error has been
 * reported in one of the standard demo tasks.  ms are converted to the equivalent
 * in ticks using the portTICK_PERIOD_MS constant. */
#define mainERROR_CHECK_TIMER_PERIOD_MS            ( 200UL / portTICK_PERIOD_MS )

/* Set mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY to 1 to create a simple demo.
 * Set mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY to 0 to create a much more
 * comprehensive test application.  See the comments at the top of this file, and
 * the documentation page on the http://www.FreeRTOS.org web site for more
 * information. */
#define mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY    0

/*-----------------------------------------------------------*/

/*
 * Set up the hardware ready to run this demo.
 */
static void prvSetupHardware( void );

/*
 * The check timer callback function, as described at the top of this file.
 */
static void prvCheckTimerCallback( TimerHandle_t xTimer );

/*
 * Configure the interrupts used to test the interrupt nesting depth as
 * described at the top of this file.
 */
static void prvSetupNestedFPUInterruptsTest( void );

/*
 * Register check tasks, and the tasks used to write over and check the contents
 * of the FPU registers, as described at the top of this file.  The nature of
 * these files necessitates that they are written in an assembly file.
 */
extern void vRegTest1Task( void * pvParameters );
extern void vRegTest2Task( void * pvParameters );
extern void vRegTestClearFlopRegistersToParameterValue( unsigned long ulValue );
extern unsigned long ulRegTestCheckFlopRegistersContainParameterValue( unsigned long ulValue );

/*
 * The task that is synchronised with the button interrupt.  This is done just
 * to demonstrate how to write interrupt service routines, and how to
 * synchronise a task with an interrupt.
 */
static void prvButtonTestTask( void * pvParameters );

/*
 * This file can be used to create either a simple LED flasher example, or a
 * comprehensive test/demo application - depending on the setting of the
 * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY constant defined above.  If
 * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY is set to 1, then the following
 * function will create a lot of additional tasks and a software timer.  If
 * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY is set to 0, then the following
 * function will do nothing.
 */
static void prvOptionallyCreateComprehensveTestApplication( void );

/*-----------------------------------------------------------*/

/* The following two variables are used to communicate the status of the
 * register check tasks to the check software timer.  If the variables keep
 * incrementing, then the register check tasks have not discovered any errors.  If
 * a variable stops incrementing, then an error has been found. */
volatile unsigned long ulRegTest1LoopCounter = 0UL, ulRegTest2LoopCounter = 0UL;

/* The following variables are used to verify that the interrupt nesting depth
 * is as intended.  ulFPUInterruptNesting is incremented on entry to an interrupt
 * that uses the FPU, and decremented on exit of the same interrupt.
 * ulMaxFPUInterruptNesting latches the highest value reached by
 * ulFPUInterruptNesting.  These variables have no other purpose. */
volatile unsigned long ulFPUInterruptNesting = 0UL, ulMaxFPUInterruptNesting = 0UL;

/* The semaphore used to demonstrate a task being synchronised with an
 * interrupt. */
static SemaphoreHandle_t xTestSemaphore = NULL;

/* The variable that is incremented by the task synchronised with the button
 * interrupt. */
volatile unsigned long ulButtonPressCounts = 0UL;

/*-----------------------------------------------------------*/

int main( void )
{
    /* Configure the hardware ready to run the test. */
    prvSetupHardware();

    /* Start standard demo/test application flash tasks.  See the comments at
     * the top of this file.  The LED flash tasks are always created.  The other
     * tasks are only created if mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY is set to
     * 0 (at the top of this file).  See the comments at the top of this file for
     * more information. */
    vStartLEDFlashTasks( mainFLASH_TASK_PRIORITY );

    /* The following function will only create more tasks and timers if
     * mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY is set to 0 (at the top of this
     * file).  See the comments at the top of this file for more information. */
    prvOptionallyCreateComprehensveTestApplication();

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* If all is well, the scheduler will now be running, and the following line
     * will never be reached.  If the following line does execute, then there was
     * insufficient FreeRTOS heap memory available for the idle and/or timer tasks
     * to be created.  See the memory management section on the FreeRTOS web site
     * for more details. */
    for( ; ; )
    {
    }
}
/*-----------------------------------------------------------*/

static void prvCheckTimerCallback( TimerHandle_t xTimer )
{
    static long lChangedTimerPeriodAlready = pdFALSE;
    static unsigned long ulLastRegTest1Value = 0, ulLastRegTest2Value = 0;
    long lErrorFound = pdFALSE;

    /* Check all the demo tasks (other than the flash tasks) to ensure
     * that they are all still running, and that none have detected an error. */

    if( xAreMathsTaskStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreIntegerMathsTaskStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreDynamicPriorityTasksStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreBlockingQueuesStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreBlockTimeTestTasksStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreGenericQueueTasksStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreRecursiveMutexTasksStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xIsCreateTaskStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xArePollingQueuesStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    if( xAreSemaphoreTasksStillRunning() != pdTRUE )
    {
        lErrorFound = pdTRUE;
    }

    /* Check that the register test 1 task is still running. */
    if( ulLastRegTest1Value == ulRegTest1LoopCounter )
    {
        lErrorFound = pdTRUE;
    }

    ulLastRegTest1Value = ulRegTest1LoopCounter;

    /* Check that the register test 2 task is still running. */
    if( ulLastRegTest2Value == ulRegTest2LoopCounter )
    {
        lErrorFound = pdTRUE;
    }

    ulLastRegTest2Value = ulRegTest2LoopCounter;

    /* Toggle the check LED to give an indication of the system status.  If
     * the LED toggles every mainCHECK_TIMER_PERIOD_MS milliseconds then
     * everything is ok.  A faster toggle indicates an error. */
    vParTestToggleLED( mainCHECK_LED );

    /* Have any errors been latch in lErrorFound?  If so, shorten the
     * period of the check timer to mainERROR_CHECK_TIMER_PERIOD_MS milliseconds.
     * This will result in an increase in the rate at which mainCHECK_LED
     * toggles. */
    if( lErrorFound != pdFALSE )
    {
        if( lChangedTimerPeriodAlready == pdFALSE )
        {
            lChangedTimerPeriodAlready = pdTRUE;

            /* This call to xTimerChangePeriod() uses a zero block time.
             * Functions called from inside of a timer callback function must
             * never* attempt	to block. */
            xTimerChangePeriod( xTimer, ( mainERROR_CHECK_TIMER_PERIOD_MS ), mainDONT_BLOCK );
        }
    }
}
/*-----------------------------------------------------------*/

static void prvButtonTestTask( void * pvParameters )
{
    configASSERT( xTestSemaphore );

    /* This is the task used as an example of how to synchronise a task with
     * an interrupt.  Each time the button interrupt gives the semaphore, this task
     * will unblock, increment its execution counter, then return to block
     * again. */

    /* Take the semaphore before started to ensure it is in the correct
     * state. */
    xSemaphoreTake( xTestSemaphore, mainDONT_BLOCK );

    for( ; ; )
    {
        xSemaphoreTake( xTestSemaphore, portMAX_DELAY );
        ulButtonPressCounts++;
    }
}
/*-----------------------------------------------------------*/

static void prvSetupHardware( void )
{
    /* Setup STM32 system (clock, PLL and Flash configuration) */
    SystemInit();

    /* Ensure all priority bits are assigned as preemption priority bits. */
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

    /* Setup the LED outputs. */
    vParTestInitialise();

    /* Configure the button input.  This configures the interrupt to use the
     * lowest interrupt priority, so it is ok to use the ISR safe FreeRTOS API
     * from the button interrupt handler. */
    STM_EVAL_PBInit( BUTTON_USER, BUTTON_MODE_EXTI );
}
/*-----------------------------------------------------------*/

void vApplicationTickHook( void )
{
    #if ( mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY == 0 )
    {
        /* Just to verify that the interrupt nesting behaves as expected,
         * increment ulFPUInterruptNesting on entry, and decrement it on exit. */
        ulFPUInterruptNesting++;

        /* Fill the FPU registers with 0. */
        vRegTestClearFlopRegistersToParameterValue( 0UL );

        /* Trigger a timer 2 interrupt, which will fill the registers with a
         * different value and itself trigger a timer 3 interrupt.  Note that the
         * timers are not actually used.  The timer 2 and 3 interrupt vectors are
         * just used for convenience. */
        NVIC_SetPendingIRQ( TIM2_IRQn );

        /* Ensure that, after returning from the nested interrupts, all the FPU
         * registers contain the value to which they were set by the tick hook
         * function. */
        configASSERT( ulRegTestCheckFlopRegistersContainParameterValue( 0UL ) );

        ulFPUInterruptNesting--;
    }
    #endif /* if ( mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY == 0 ) */
}
/*-----------------------------------------------------------*/

static void prvSetupNestedFPUInterruptsTest( void )
{
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Enable the TIM2 interrupt in the NVIC.  The timer itself is not used,
     * just its interrupt vector to force nesting from software.  TIM2 must have
     * a lower priority than TIM3, and both must have priorities above
     * configMAX_SYSCALL_INTERRUPT_PRIORITY. */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY - 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );

    /* Enable the TIM3 interrupt in the NVIC.  The timer itself is not used,
     * just its interrupt vector to force nesting from software.  TIM2 must have
     * a lower priority than TIM3, and both must have priorities above
     * configMAX_SYSCALL_INTERRUPT_PRIORITY. */
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY - 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );
}
/*-----------------------------------------------------------*/

void TIM3_IRQHandler( void )
{
    /* Just to verify that the interrupt nesting behaves as expected, increment
     * ulFPUInterruptNesting on entry, and decrement it on exit. */
    ulFPUInterruptNesting++;

    /* This is the highest priority interrupt in the chain of forced nesting
     * interrupts, so latch the maximum value reached by ulFPUInterruptNesting.
     * This is done purely to allow verification that the nesting depth reaches
     * that intended. */
    if( ulFPUInterruptNesting > ulMaxFPUInterruptNesting )
    {
        ulMaxFPUInterruptNesting = ulFPUInterruptNesting;
    }

    /* Fill the FPU registers with 99 to overwrite the values written by
     * TIM2_IRQHandler(). */
    vRegTestClearFlopRegistersToParameterValue( 99UL );

    ulFPUInterruptNesting--;
}
/*-----------------------------------------------------------*/

void TIM2_IRQHandler( void )
{
    /* Just to verify that the interrupt nesting behaves as expected, increment
     * ulFPUInterruptNesting on entry, and decrement it on exit. */
    ulFPUInterruptNesting++;

    /* Fill the FPU registers with 1. */
    vRegTestClearFlopRegistersToParameterValue( 1UL );

    /* Trigger a timer 3 interrupt, which will fill the registers with a
     * different value. */
    NVIC_SetPendingIRQ( TIM3_IRQn );

    /* Ensure that, after returning from the nesting interrupt, all the FPU
     * registers contain the value to which they were set by this interrupt
     * function. */
    configASSERT( ulRegTestCheckFlopRegistersContainParameterValue( 1UL ) );

    ulFPUInterruptNesting--;
}
/*-----------------------------------------------------------*/

static void prvOptionallyCreateComprehensveTestApplication( void )
{
    #if ( mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY == 0 )
    {
        TimerHandle_t xCheckTimer = NULL;

        /* Configure the interrupts used to test FPU registers being used from
         * nested interrupts. */
        prvSetupNestedFPUInterruptsTest();

        /* Start all the other standard demo/test tasks. */
        vStartIntegerMathTasks( tskIDLE_PRIORITY );
        vStartDynamicPriorityTasks();
        vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
        vCreateBlockTimeTasks();
        vStartCountingSemaphoreTasks();
        vStartGenericQueueTasks( tskIDLE_PRIORITY );
        vStartRecursiveMutexTasks();
        vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );
        vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );

        /* Most importantly, start the tasks that use the FPU. */
        vStartMathTasks( mainFLOP_TASK_PRIORITY );

        /* Create the register check tasks, as described at the top of this
         * file */
        xTaskCreate( vRegTest1Task, "Reg1", configMINIMAL_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, NULL );
        xTaskCreate( vRegTest2Task, "Reg2", configMINIMAL_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, NULL );

        /* Create the semaphore that is used to demonstrate a task being
         * synchronised with an interrupt. */
        vSemaphoreCreateBinary( xTestSemaphore );

        /* Create the task that is unblocked by the demonstration interrupt. */
        xTaskCreate( prvButtonTestTask, "BtnTest", configMINIMAL_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, NULL );

        /* Create the software timer that performs the 'check' functionality,
         * as described at the top of this file. */
        xCheckTimer = xTimerCreate( "CheckTimer",                  /* A text name, purely to help debugging. */
                                    ( mainCHECK_TIMER_PERIOD_MS ), /* The timer period, in this case 3000ms (3s). */
                                    pdTRUE,                        /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
                                    ( void * ) 0,                  /* The ID is not used, so can be set to anything. */
                                    prvCheckTimerCallback          /* The callback function that inspects the status of all the other tasks. */
                                    );

        if( xCheckTimer != NULL )
        {
            xTimerStart( xCheckTimer, mainDONT_BLOCK );
        }

        /* This task has to be created last as it keeps account of the number of
         * tasks it expects to see running. */
        vCreateSuicidalTasks( mainCREATOR_TASK_PRIORITY );
    }
    #else /* mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY */
    {
        /* Just to prevent compiler warnings when the configuration options are
         * set such that these static functions are not used. */
        ( void ) vRegTest1Task;
        ( void ) vRegTest2Task;
        ( void ) prvCheckTimerCallback;
        ( void ) prvSetupNestedFPUInterruptsTest;
    }
    #endif /* mainCREATE_SIMPLE_LED_FLASHER_DEMO_ONLY */
}
/*-----------------------------------------------------------*/

void EXTI9_5_IRQHandler( void )
{
    long lHigherPriorityTaskWoken = pdFALSE;

    /* Only line 6 is enabled, so there is no need to test which line generated
     * the interrupt. */
    EXTI_ClearITPendingBit( EXTI_Line6 );

    /* This interrupt does nothing more than demonstrate how to synchronise a
     * task with an interrupt.  First the handler releases a semaphore.
     * lHigherPriorityTaskWoken has been initialised to zero. */
    xSemaphoreGiveFromISR( xTestSemaphore, &lHigherPriorityTaskWoken );

    /* If there was a task that was blocked on the semaphore, and giving the
     * semaphore caused the task to unblock, and the unblocked task has a priority
     * higher than the currently executing task (the task that this interrupt
     * interrupted), then lHigherPriorityTaskWoken will have been set to pdTRUE.
     * Passing pdTRUE into the following macro call will cause this interrupt to
     * return directly to the unblocked, higher priority, task. */
    portEND_SWITCHING_ISR( lHigherPriorityTaskWoken );
}
/*-----------------------------------------------------------*/

void vApplicationMallocFailedHook( void )
{
    /* vApplicationMallocFailedHook() will only be called if
     * configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
     * function that will get called if a call to pvPortMalloc() fails.
     * pvPortMalloc() is called internally by the kernel whenever a task, queue,
     * timer or semaphore is created.  It is also called by various parts of the
     * demo application.  If heap_1.c or heap_2.c are used, then the size of the
     * heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
     * FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
     * to query the size of free heap space that remains (although it does not
     * provide information on how the remaining heap might be fragmented). */
    taskDISABLE_INTERRUPTS();

    for( ; ; )
    {
    }
}
/*-----------------------------------------------------------*/

void vApplicationIdleHook( void )
{
    /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
     * to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
     * task.  It is essential that code added to this hook function never attempts
     * to block in any way (for example, call xQueueReceive() with a block time
     * specified, or call vTaskDelay()).  If the application makes use of the
     * vTaskDelete() API function (as this demo application does) then it is also
     * important that vApplicationIdleHook() is permitted to return to its calling
     * function, because it is the responsibility of the idle task to clean up
     * memory allocated by the kernel to any task that has since been deleted. */
}
/*-----------------------------------------------------------*/

void vApplicationStackOverflowHook( TaskHandle_t pxTask,
                                    char * pcTaskName )
{
    ( void ) pcTaskName;
    ( void ) pxTask;

    /* Run time stack overflow checking is performed if
     * configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
     * function is called if a stack overflow is detected. */
    taskDISABLE_INTERRUPTS();

    for( ; ; )
    {
    }
}
/*-----------------------------------------------------------*/
